﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;

namespace AsianOptionsService
{
    public class LookBackOption : BasedOptions
    {
        public LookBackOption() { }

        public LookBackOption(int typeId, int dayNum, double interest, double initial, double exercise, double up, double down,
            double deltaT, double threshold, bool isCall, bool isFixed, bool isUp, int isAverage, int otherChoice, double var, int brownApproxiMethod)
        {
            this.typeId = typeId;

            this.dayNum = dayNum;

            this.interest = interest;

            this.initial = initial;

            this.exercise = exercise;

            this.up = up;

            this.down = down;

            this.deltaT = deltaT;

            this.threshold = threshold;

            this.isCall = isCall;

            this.isFixed = isFixed;

            this.isUp = isUp;

            this.isAverage = isAverage;

            this.otherChoice = otherChoice;

            this.var = var;

            this.brownApproxiMethod = brownApproxiMethod;
        }

        public override double compute_price(int runs, int periods, int clientId)
        {
            double[] pricePath = new double[periods + 1];

            // Risk-neutral probabilities
            double piup = (interest - down) / (up - down);
            double pidown = 1 - piup;

            double temp = 0.0;

            Random rand = new Random(clientId * 100);
            //double priceAverage = 0.0;
            double callPayOff = 0.0;
            //double sumPayOff = 0.0;
            //double sumSquarePayOff = 0.0;
            double premium = 1.18;
            double[] payOffArray = new double[runs];

            int[] distribution = new int[100];
            for (int index = 0; index < runs; index++)
            {
                // Generate Path
                double maxPrice = initial;
                double minPrice = initial;
                if (brownApproxiMethod == 0)
                {
                    for (int i = 1; i <= periods; i++)
                    {
                        pricePath[0] = initial;
                        double rn = rand.NextDouble();

                        if (rn > pidown)
                        {
                            pricePath[i] = pricePath[i - 1] * up;
                        }
                        else
                        {
                            pricePath[i] = pricePath[i - 1] * down;
                        }
                        if (pricePath[i] > maxPrice)
                        {
                            maxPrice = pricePath[i];
                        }
                        if (pricePath[i] < minPrice)
                        {
                            minPrice = pricePath[i];
                        }
                    }
                }
                else if (brownApproxiMethod == 1)
                {
                    for (int i = 1; i <= periods; i++)
                    {
                        pricePath[0] = initial;
                        pricePath[i] = nextPrice(pricePath[i - 1], rand, sigma, interest, deltaT);
                        if (pricePath[i] > maxPrice)
                        {
                            maxPrice = pricePath[i];
                        }
                        if (pricePath[i] < minPrice)
                        {
                            minPrice = pricePath[i];
                        }
                    }
                }
                
                if (index % 10000 == 0)
                {
                    Log("pathId:" + (clientId * 5000000 / 32 + index / 10000) + "\r\n", clientId);
                    for (int i = 0; i <= periods; i++)
                        if (i != periods)
                            Log(pricePath[i] + "->", clientId);
                        else
                            Log(pricePath[i] + "\r\n\r\n", clientId);
                }
                if (isFixed)
                {
                    if (isCall) 
                        callPayOff = Math.Max(maxPrice - exercise, 0);
                    else
                        callPayOff = Math.Max(exercise-minPrice, 0);
                }
                else
                {
                    if (isCall)
                        callPayOff = pricePath[periods]-minPrice;
                    else
                        callPayOff = maxPrice-pricePath[periods];
                }
               

                temp += callPayOff;
                payOffArray[index] = callPayOff;
                //sumPayOff += callPayOff / Math.Pow(interest, periods);
                //sumSquarePayOff += callPayOff * callPayOff / Math.Pow(interest, 2 * periods);
                int di = (int)(callPayOff / Math.Pow(interest, periods) * 20 / premium);
                if (di > 99)
                    di = 99;
               distribution[di]++;
            }

            double avgValue = (temp / Math.Pow(interest, periods)) / runs;
            double stdDev = 0;
            for (int i = 0; i < runs; i++)
                stdDev += Math.Pow((payOffArray[i] / Math.Pow(interest, periods) / avgValue - 1), 2);
            stdDev = Math.Sqrt(stdDev) / ((runs == 1) ? 1 : runs - 1);


            ////double stdDev = Math.Sqrt(sumSquarePayOff - sumPayOff * sumPayOff / runs) / ((runs == 1) ? 1 : runs - 1);
            double stdErr = stdDev / Math.Sqrt(runs);
            Log(string.Format("stdDev :{0:0.0000} stdErr :{1:0.0000}\r\n", stdDev, stdErr), clientId);
            for (int i = 0; i < 100; i++)
                Log(distribution[i]+" ", clientId);
            Log("\r\n", clientId);
                //double returnValue = (temp / Math.Pow(interest, periods)) / runs;
                return avgValue;
        }
    }

}